<?php

/**
 * @see Zend_Controller_Plugin_Abstract
 */
require_once 'Zend/Controller/Plugin/Abstract.php';

/**
 * Classe para configuracao da view baseado na requisicao.
 *
 * @category Tavs
 * @package Tavs_Controller_Plugin_View
 *
 * @uses Tavs_View_Helper_BaseUrl
 *
 * @author Tales Santos <tales.augusto.santos>
 */
class Tavs_Controller_Plugin_View extends Zend_Controller_Plugin_Abstract
{
	/**
	 * Nome da pasta dos arquivos JS
	 *
	 * @var string
	 */
	protected $_scriptPathName = 'scripts';

	/**
	 * Nome do script a nivel de controller
	 *
	 * @var string
	 */
	protected $_scriptControllerName = 'controller';

	/**
	 * Nome da pasta dos arquivos CSS
	 *
	 * @var string
	 */
	protected $_stylePathName  = 'styles';

	/**
	 * Nome do style a nivel de controller
	 *
	 * @var string
	 */
	protected $_styleControllerName = 'controller';

	/**
	 * Objeto de renderizaca
	 *
	 * @var Zend_View_Interface
	 */
	protected $_view;

	/**
	 * Nome da variavel a ser utilizada no javascript
	 *
	 * @var string
	 */
	protected $_phpVarsName = 'phpVars';

	/**
	 * Variaveis passadas ao javascript
	 *
	 * @var array
	 */
	protected $_phpVars = array();

	/**
	 * Carregar as variaveis default?
	 *
	 * @var bool
	 */
	protected $_loadDefaultPhpVars = true;

	/**
	 * Construtor
	 *
	 * @param array|Zend_Config $options Opcoes a serem configuradas
	 *
	 * @return void
	 */
	public function __construct($options = array())
	{
		if ($options instanceof Zend_Config) {
			$options = $options->toArray();
		}
		$this->setOptions($options);
	}

	/**
	 * Seta as opcoes do plugin
	 *
	 * @param array $options
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setOptions(array $options)
	{
		foreach ($options as $optName => $optValue) {
			$method = 'set' . ucfirst($optName);
			if (method_exists($this, $method)) {
				$this->$method($optValue);
			}
			else {
				$this->addPhpVar($optName, $optValue);
			}
		}

		return $this;
	}

	/**
	 * Seta o nome da pasta de scripts JS
	 *
	 * @param string $scriptPathName
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setScriptPathName($scriptPathName)
	{
		$this->_scriptPathName = (string) $scriptPathName;
		return $this;
	}

	/**
	 * Seta o nome do arquivo JS a nivel de controller.
	 *
	 * Obs: sem o sufixo .js
	 *
	 * @param string $scriptControllerName
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setScriptControllerName($scriptControllerName)
	{
		$this->_scriptControllerName = (string) $scriptControllerName;
		return $this;
	}

	/**
	 * Seta o nome da pasta de estilos
	 *
	 * @param string $stylePathName
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setStylePathName($stylePathName)
	{
		$this->_stylePathName = (string) $stylePathName;
		return $this;
	}

	/**
	 * Seta o nome do arquivo CSS a nivel de controller
	 *
	 * Obs: sem o sufixo .css
	 *
	 * @param string $styleControllerName
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setStyleControllerName($styleControllerName)
	{
		$this->_styleControllerName = (string) $styleControllerName;
		return $this;
	}

	/**
	 * Seta o nome da variavel a ser usada no JS.
	 *
	 * @param string $name Nome da variavel
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setPhpVarsName($name)
	{
		$this->_phpVarsName = (string)$name;
		return $this;
	}

	/**
	 * Seta o array com as variaveis que serao passadas para o JS.
	 *
	 * @param array $vars Array chave=>valor com as variaveis
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setPhpVars(array $vars)
	{
		$this->_phpVars = array();
		$this->addPhpVar($vars);
		return $this;
	}

	/**
	 * Define se ira ser carregado as variaveis padroes do PHP para
	 * serem incluidas em phpVars
	 *
	 * @param bool $bool
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function setLoadDefaultPhpVars($bool)
	{
		$this->_loadDefaultPhpVars = (bool)$bool;
		return $this;
	}

	/**
	 * Adiciona uma variavel que sera utilizada no JS.
	 *
	 * @param string|array $name Nome da variavel ou array de variaveis a serem adicionadas
	 * @param mixed $var Valor da variavel Valor da variavel
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	public function addPhpVar($name, $var = null)
	{
		if (is_array($name)) {
			foreach ($name as $key => $val) {
				$this->addPhpVar($key, $val);
			}
		}
		else {
			$this->_phpVars[(string) $name] = $var;
		}
		return $this;
	}

	/**
	 * Adiciona variaveis uteis ao javascript
	 *
	 * @return void
	 */
	public function routeStartup()
	{
		$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');

		$view = $viewRenderer->view;

		if (!$view instanceof Zend_View_Interface) {
			throw new Zend_Controller_Exception('objeto de visualizacao nao foi configurado ainda');
		}

		$this->_view = $view;

		$this->_loadDefaultPhpVars();

		$phpVars = $this->_phpVars;

		//adiciona ao cabeçalho variaveis geradas pelo php
		if (count($phpVars)) {
			$script = 'var ' . $this->_phpVarsName . ' = ' . Zend_Json::encode($phpVars) . ';' . PHP_EOL;
			$view->headScript()->appendScript($script);
		}

	}

	/**
	 * Carrega as variaveis default
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	private function _loadDefaultPhpVars()
	{
		if ($this->_loadDefaultPhpVars) {

			$view = $this->_view;
			$baseUrl = $view->baseUrl();

			$phpVars = array(
				'baseUrl' => $baseUrl,
				'paths' => array(
					'scripts' => $baseUrl . '/commons/scripts',
					'styles'  => $baseUrl . '/commons/styles',
					'images'  => $baseUrl . '/commons/images'
				)
			);

			if (Zend_Session::isStarted()) {
				$phpVars['PHPSESSID'] = Zend_Session::getId();
			}

			$this->addPhpVar($phpVars);
		}

		return $this;
	}

	/**
	 * Adiciona os arquivos especificos
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 */
	public function postDispatch(Zend_Controller_Request_Abstract $request)
	{
		//adiciona sempre após o ultimo dispacth
		if ($request->isDispatched())
		{
			//parametros do request
			$module     = $request->getModuleName();
			$controller = $request->getControllerName();
			$action     = $request->getActionName();

			$scripts = array();
			$styles  = array();

			//script nivel de modulo
			$scripts[] = $module . '/' . $this->_scriptPathName . '/' . $module . '.js';

			//script nivel de controller
			$scripts[] = $module . '/' . $this->_scriptPathName . '/' . $controller . '/' . $this->_scriptControllerName . '.js';

			//script nivel de action
			$scripts[] = $module . '/' . $this->_scriptPathName . '/' . $controller . '/' . $action . '.js';

			//style nivel de modulo
			$styles[] = $module . '/' . $this->_stylePathName . '/' . $module . '.css';

			//style nivel de controller
			$styles[] = $module . '/' . $this->_stylePathName . '/' . $controller . '/' . $this->_styleControllerName . '.css';

			//style nivel de action
			$styles[] = $module . '/' . $this->_stylePathName . '/' . $controller . '/' . $action . '.css';

			//adiciona os scripts no header
			$this
				->_appendStylesheet($styles)
				->_appendScript($scripts);
		}
	}

	/**
	 * Adiciona script JS ao cabecalho
	 *
	 * @param string|array $script String ou array com os nomes dos arquivos a serem adicionados
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	protected function _appendScript($script)
	{
		if (is_array($script)) {
			foreach ($script as $fileName) {
				$this->_appendScript($fileName);
			}
		}
		else {
			$view = $this->_view;
			$script = (string) $script;
			if (file_exists($script)) {
				$view->headScript()->appendFile($view->baseUrl('/' . $script));
			}
		}

		return $this;
	}

	/**
	 * Adiciona os arquivos CSS ao cabecalho
	 *
	 * @param string|array $script String ou array com os nomes dos arquivos a serem adicionados
	 *
	 * @return Tavs_Controller_Plugin_View
	 */
	protected function _appendStylesheet($stylesheet)
	{
		if (is_array($stylesheet)) {
			foreach ($stylesheet as $fileName) {
				$this->_appendStylesheet($fileName);
			}
		}
		else {
			$view = $this->_view;
			$stylesheet = (string) $stylesheet;
			if (file_exists($stylesheet)) {
				$view->headLink()->appendStylesheet($view->baseUrl('/' . $stylesheet));
			}
		}

		return $this;
	}
}